<?php if (!defined('BASEPATH')) exit ('No direct script access allowed');

include_once('ExceptionDAO.php');
include_once('ExceptionPermissao.php');
include_once 'util/MapError.php';
include_once 'TOUsuario.php';
include_once 'TOAcao.php';

/**
 * DAO para operações de banco para Administrador
 * @author Douglas Rafael
 *
 */
class DAOUsuario extends CI_Model {
    
    /**
     * Lista todos os usuários cadastrados.
     * 
     * @param int    $init      Posição inicial do cursor
     * @param int    $quant     Total de registros
     * @param string $orderby   Nome da coluna a ser ordenada
     * @param string $direction Direção: ASC ou DESC
     * @return array
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function select_all_users($init, $quant, $orderby = NULL, $direction = NULL) {
        try {
            $orderby != NULL && $direction != NULL ? $this->db->order_by($orderby, $direction) : $this->db->order_by('id', 'ASC');
            $result = $this->db->get('usuario', $quant, $init);

            //Caso ocorra erro no select
            if (!$result) {
                throw new ExceptionDAO('Ocorreu um erro de banco de dados ao tentar listar os usuários.');
            } else {
                $usuarios = array();
                foreach ($result->result() as $value) {
                    $usuario = new TOUsuario();
                    $usuario->id = $value->id;
                    $usuario->nome = $value->nome;
                    $usuario->sobrenome = $value->sobrenome;
                    $usuario->email = $value->email;
                    $usuario->senha = $value->senha;
                    $usuario->imagem = $value->imagem;
                    $usuario->data_nascimento = $value->data_nascimento;
                    $usuario->data_cadastro = $value->data_cadastro;
                    $usuario->ultimo_login = $value->ultimo_login;
                    $usuario->quantidade_login = $value->quantidade_login;
                    $usuario->status = $value->status;
                    $usuario->motivo_inatividade = $value->motivo_inatividade;
                    
                    array_push($usuarios, $usuario);
                }
                return $usuarios;
            }
        } catch (ExceptionDAO $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    /**
     * Seleciona usuário de acordo com o id
     * 
     * @param  int    $id_usuario  id do usuário a ser selecionado
     * @param  string $email       e-mail do usuário a ser selecionado. Caso não seja pelo id seleciona pelo e-mail
     * @return TOUsuario        Array de objeto
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function get_user($id_usuario, $email = NULL) {
        try {
            $email != NULL ? $this->db->where("email", $email) : $this->db->where("id", $id_usuario);
            $result = $this->db->get('usuario', 1);
            
            //Caso ocorra erro no select
            if (!$result) {
                throw new Exception('Ocorreu um erro de banco de dados ao tentar selecionar usuário.');
            } else {
                $value = $result->row();
                if (count($value) > 0) {
                    $usuario = new TOUsuario();
                    $usuario->id = $value->id;
                    $usuario->nome = $value->nome;
                    $usuario->sobrenome = $value->sobrenome;
                    $usuario->email = $value->email;
                    $usuario->senha = $value->senha;
                    $usuario->imagem = $value->imagem;
                    $usuario->data_cadastro = $value->data_cadastro;
                    $usuario->data_nascimento = $value->data_nascimento;
                    $usuario->ultimo_login = $value->ultimo_login;
                    $usuario->quantidade_login = $value->quantidade_login;
                    $usuario->status = $value->status;
                    $usuario->motivo_inatividade = $value->motivo_inatividade;

                    $this->load->model('DAOGrupo');
                    $usuario->grupos = $this->DAOGrupo->get_groups_user($usuario->id);

                    return $usuario;
                } else {
                    throw new ExceptionValidacao('Usuário não foi encontrado na base de dados...');
                }
            }
            
        } catch (ExceptionValidacao $e) {
            throw new ExceptionValidacao($e->getMessage());
        } catch (ExceptionDAO $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    
    /**
     * Insere usuário no banco
     * 
     * @param TOUsuario $usuario    Objeto com dados do usuário
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function insert_user(TOUsuario $usuario) {
        try {
            $this->db->trans_start();

            $this->db->set('nome', $usuario->nome);
            $this->db->set('sobrenome', $usuario->sobrenome);
            $this->db->set('email', $usuario->email);
            $this->db->set('senha', md5($usuario->senha));
            $this->db->set('imagem', $usuario->imagem);
            $this->db->set('data_cadastro', $usuario->data_cadastro);
            $this->db->set('data_nascimento', $usuario->data_nascimento);
            $this->db->set('status', $usuario->status);
            $this->db->set('motivo_inatividade', $usuario->motivo_inatividade);
            $result = $this->db->insert('usuario');

            if (!$result) {
                //Traduz o tipo de erro de acordo com $num
                $erro = new MapError();
                throw new Exception($erro->getError($this->db->_error_number(), $this->db->_error_message(), $usuario->nome));
            } else {
                $usuario->id = $this->db->insert_id(); // Pegendo o id do item inserido
                //Insere os grupos do usuário
                $this->load->model('DAOGrupo');
                $this->DAOGrupo->insert_group_user($usuario);
                
                if ($this->db->trans_status() === FALSE) {
                    throw new Exception('Ocorreu um erro de banco de dados ao tentar inserir o usuário.');
                }
            }
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    /**
     * Atualiza dados do usuário
     * 
     * @param TOUsuario $usuario
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function update_user(TOUsuario $usuario) {
        try {
            $this->db->trans_start();

            $this->db->set('nome', $usuario->nome);
            $this->db->set('sobrenome', $usuario->sobrenome);
            $this->db->set('email', $usuario->email);
            $usuario->senha != NULL ? $this->db->set('senha', md5($usuario->senha)) : '';
            $usuario->imagem != NULL ? $this->db->set('imagem', $usuario->imagem) : '';
            $this->db->set('data_nascimento', $usuario->data_nascimento);
            $this->db->set('status', $usuario->status);
            $this->db->set('motivo_inatividade', $usuario->motivo_inatividade);
            $this->db->where('id', $usuario->id);
            $result = $this->db->update('usuario');

            if (!$result) {
                //Traduz o tipo de erro de acordo com $num
                $erro = new MapError();
                throw new Exception($erro->getError($this->db->_error_number(), $this->db->_error_message(), $usuario->nome));
            } else {
                //Insere os grupos do usuário
                $this->load->model('DAOGrupo');
                $this->DAOGrupo->update_group_user($usuario);
                
                if ($this->db->trans_status() === FALSE) {
                    throw new Exception('Ocorreu um erro de banco de dados ao tentar atualizar o usuário: <span class="bold">' . $usuario->nome . ' ' . $usuario->sobrenome . '</span>');
                }
            }
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    /**
     * 
     * @param type $password
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function update_password(TOUsuario $usuario) {
        try {
            $this->db->set('senha', md5($usuario->senha));
            $this->db->where('id', $usuario->id);
            $result = $this->db->update('usuario');

            if (!$result) {
                //Traduz o tipo de erro de acordo com $num
                $erro = new MapError();
                throw new Exception($erro->getError($this->db->_error_number(), $this->db->_error_message(), $usuario->nome));
            }
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }

    /**
     * Autenticar usuário
     * 
     * @param string login      Login do usuario
     * @param string password   Senha
     * @throws ExceptionDAO 
     */
    public function autenticarUser(TOUsuario $usuario) {
        try {
            $this->db->trans_start();

            $this->db->select('id, nome, sobrenome, status, motivo_inatividade, ultimo_login, quantidade_login');
            $this->db->where('email', $usuario->login);
            $this->db->where('senha', md5($usuario->senha));

            $result = $this->db->get('usuario', 1);
            if (!$result) {
                throw new ExceptionDAO('Ocorreu um erro de banco de dados ao tentar fazer a autenticação.');
            } else {
                if ($result->num_rows() == 1) {
                    $value = $result->row();
                    //Verifica se o usuário estar inativo
                    if ($value->status == TOUsuario::USER_INATIVO) {
                        throw new ExceptionValidacao('<b>Usuário está INATIVO!</b><br /><i>Não é possível efetuar o login.</i><p>' . $value->motivo_inatividade . '</p>');
                    } else {
                        $usuario = new TOUsuario();
                        $usuario->id = $value->id;
                        $usuario->nome = $value->nome;
                        $usuario->sobrenome = $value->sobrenome;
                        $usuario->ultimo_login = $value->ultimo_login;
                        $usuario->quantidade_login = $value->quantidade_login;

                        $this->mark_login($usuario);
                        $usuario->super_admin = $this->check_super_admin($usuario);

                        if ($this->db->trans_status() === FALSE) {
                            throw new Exception('Ocorreu um erro de banco de dados ao tentar inserir o usuário.');
                        } else {
                            return $usuario;
                        }
                    }
                } else {
                    throw new ExceptionValidacao('<b>Login ou Password incorreto.</b> <br />Tente novamente!');
                }
            }
        } catch (ExceptionValidacao $e) {
            throw new ExceptionValidacao($e->getMessage());
        } catch (ExceptionDAO $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    /**
     * Salva a data e hora do login
     * 
     * @param TOUsuario $usuario        Objeto usuário contendo os dados
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function mark_login(TOUsuario $usuario) {
        try {
            $this->db->set('ultimo_login', date('Y-m-d H:i:s'));
            $this->db->set('quantidade_login', $usuario->quantidade_login += 1);
            $this->db->where('id', $usuario->id);
            $result = $this->db->update('usuario');

            if (!$result) {
                throw new Exception('Ocorreu um erro ao tentar gravar dados do usuário');
            }
            $this->db->trans_complete();
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    /**
     * Verifica se o usuário logado tem Ação de SUPER ADMINISTRADOR
     * 
     * @param TOUsuario $usuario        Objeto usuário contendo os dados
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function check_super_admin(TOUsuario $usuario) {
        try {
            $result_query = $this->db->query('
                                  SELECT
                                    IF(
                                      acao_has_grupo.acao_id = 0,
                                      TRUE,
                                      FALSE
                                    ) AS super_admin
                                  FROM
                                      usuario 
                                  JOIN grupo_has_usuario 
                                       ON grupo_has_usuario.usuario_id = usuario.id 
                                  JOIN acao_has_grupo 
                                       ON acao_has_grupo.grupo_id = `grupo_has_usuario`.`grupo_id` 
                                  WHERE usuario.id = ' . $usuario->id,
                                  ' GROUP BY usuario.id');
            
            if (!$result_query) {
                throw new Exception('Ocorreu um erro ao tentar verificar se o usuário possui ação de SUPER ADMINISTRADOR');
            } else {
                $result = $result_query->row();
                return $result->super_admin;
            }
            $this->db->trans_complete();
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    /**
     * Retorna o Total geral de itens que o usuário cadastrou
     * 
     * @return int Total de resgistros
     */
    public function amount_itens_users($id_user) {
        $this->db->select('item.codigo');
        $this->db->join('usuario', 'usuario.id = item.usuario_admin_id');
        $this->db->where('usuario.id', $id_user);
        $result = $this->db->get('item');
        
        return count($result->result());
    }

    /**
     * Retorna o Total geral usuários cadastrados.
     * 
     * @return int Total de resgistros
     */
    public function amount_all_users() {
        $this->db->select('id');
        return $this->db->count_all_results('usuario');
    }
    
    
    /**
     * Efetua busca por usuário
     * 
     * @param type $init
     * @param type $quant
     * @param type $term
     * @param type $orderby
     * @param type $direction
     * @return array
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function search_user($init, $quant, $term = NULL, $orderby = NULL, $direction = NULL) {
        try {
            $this->load->helper('string_util');
            // Se conter os caracteres / ou - o termo da busca é tratado como data
            if ((strstr($term, "/")) || (strstr($term, "-"))) {
                $term = format_date($term);
            }
            $this->db->select('usuario.id, usuario.nome, usuario.sobrenome, usuario.email, usuario.senha, usuario.imagem, usuario.data_nascimento, usuario.data_cadastro,
                usuario.ultimo_login, usuario.quantidade_login, usuario.status, usuario.motivo_inatividade');
            $this->db->join('grupo_has_usuario', 'grupo_has_usuario.usuario_id = usuario.id');
            $this->db->join('grupo', 'grupo.id = grupo_has_usuario.grupo_id');
            $this->db->like('usuario.id', $term);
            $this->db->or_like('usuario.nome', $term);
            $this->db->or_like('usuario.sobrenome', $term);
            $this->db->or_like('usuario.email', $term);
            $this->db->or_like('usuario.data_cadastro', $term);
            $this->db->or_like('grupo.nome', $term);
            $this->db->group_by('usuario.id');
            $orderby != NULL && $direction != NULL ? $this->db->order_by($orderby, $direction) : $this->db->order_by('id', 'ASC');
            $result = $this->db->get('usuario', $quant, $init);

            //Caso ocorra erro no select
            if (!$result) {
                throw new Exception('Ocorreu um erro de banco de dados ao tentar buscar usuário.');
            } else {
                $usuarios = array();
                foreach ($result->result() as $value) {
                    $usuario = new TOUsuario();
                    $usuario->id = $value->id;
                    $usuario->nome = $value->nome;
                    $usuario->sobrenome = $value->sobrenome;
                    $usuario->email = $value->email;
                    $usuario->senha = $value->senha;
                    $usuario->imagem = $value->imagem;
                    $usuario->data_nascimento = $value->data_nascimento;
                    $usuario->data_cadastro = $value->data_cadastro;
                    $usuario->ultimo_login = $value->ultimo_login;
                    $usuario->quantidade_login = $value->quantidade_login;
                    $usuario->status = $value->status;
                    $usuario->motivo_inatividade = $value->motivo_inatividade;
                    
                    array_push($usuarios, $usuario);
                }
                return $usuarios;
            }
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
     /**
     * Retorna a quantidade de registros da busca
     * 
     * @param string $term
     * @return int
     */
    public function amount_search_user($term) {
        $this->load->helper('string_util');
        // Se conter os caracteres / ou - o termo da busca é tratado como data
        if ((strstr($term, "/")) || (strstr($term, "-"))) {
            $term = format_date($term);
        }

        $this->db->select('usuario.id, usuario.nome, usuario.sobrenome, usuario.email, usuario.senha, usuario.imagem, usuario.data_nascimento, usuario.data_cadastro,
                usuario.ultimo_login, usuario.quantidade_login, usuario.status, usuario.motivo_inatividade');
        $this->db->join('grupo_has_usuario', 'grupo_has_usuario.usuario_id = usuario.id');
        $this->db->join('grupo', 'grupo.id = grupo_has_usuario.grupo_id');
        $this->db->like('usuario.id', $term);
        $this->db->or_like('usuario.nome', $term);
        $this->db->or_like('usuario.sobrenome', $term);
        $this->db->or_like('usuario.email', $term);
        $this->db->or_like('usuario.data_cadastro', $term);
        $this->db->or_like('grupo.nome', $term);
        $this->db->group_by('usuario.id');

        $result = $this->db->get('usuario');
        
        return count($result->result());
    }
    
    
    /**
     * Excluir usuário de acordo com o id.
     * 
     * @param TOUsuario $usuario Obejto usuário
     * @throws ExceptionDAO 
     */
    public function delete_user(TOUsuario $usuario) {
        try {
            $this->db->where_in('id', $usuario->id);
            $result = $this->db->delete('usuario');

            if (!$result) {
                throw new Exception();
            } else {
                if (!empty($usuario->imagem)) {
                    $this->load->model('UploadImage');
                    $this->UploadImage->delete_image($this->config->item('path_img_user'), $usuario->imagem);
                }
            }
        } catch (Exception $e) {
            //Traduz o tipo de erro de acordo com $num
            $erro = new MapError();
            throw new ExceptionDAO($erro->getError($this->db->_error_number(), $this->db->_error_message(), $usuario->nome));
        }
    }    
    
    /**
     * Verifica se um usuário tem permissão de executar uma ação.
     * @param int $idUsuario    id do usuário
     * @param int $idAcao       id da ação
     * @return bool             retorna TRUE se tiver permição e FALSE se não
     */
    public function temPermissao($idUsuario, $idAcao) {
        try {
            $this->db->select('COUNT(*) as total');
            $this->db->join('grupo g', 'g.id = gu.grupo_id');
            $this->db->join('acao_has_grupo ag', 'ag.grupo_id = g.id');
            $this->db->where('gu.usuario_id', $idUsuario);
            $this->db->where('g.status', 1);
            $this->db->where('(ag.acao_id = ' . $idAcao . ' OR ag.acao_id = ' . TOAcao::TODAS_ACOES . ')');
            $result = $this->db->get('grupo_has_usuario gu', 1);
            
            if (!$result) {
                throw new Exception('Ocorreu um erro de banco de dados ao tentar verificar permissões.');
            } else {
                foreach ($result->result() as $value) {
                    return $value->total == 1 ? TRUE : FALSE;
                }
            }
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    /**
     * Retorna sugestões de usuários de acordo com o term digitado
     * Útil para utilizar no autocomplete
     * 
     * @param  string   Termo da busca
     * @return array    Array contendo usuários
     */
    public function suggestion_users($term) {
        $this->db->select('id, nome, sobrenome, email, imagem');
        $this->db->like('nome', $term);
        $this->db->or_like('sobrenome', $term);
        $this->db->or_like('email', $term);
        $result = $this->db->get('usuario');

        $usuarios = array();
        if ($result) {
            foreach ($result->result() as $value) {
                $data['value'] = $value->nome . ' ' . $value->sobrenome;
                $data['label'] = $value->nome . ' ' . $value->sobrenome;
                $data['id'] = $value->id;
                $data['email']  = $value->email;
                $data['image'] = $value->imagem;
                array_push($usuarios, $data);
            }
            return $usuarios;
        }
    }
    
    
    /**
     * retorna todos e-mails dos usuários cadastrados
     * 
     * @return array    Array contendo os dados
     */
    public function get_emails_user() {
        try {
            $this->db->select('email');
            $result = $this->db->get('usuario');

            //Caso ocorra erro no select
            if (!$result) {
                throw new ExceptionDAO('Ocorreu um erro de banco de dados ao tentar montar lista com e-mail de todos usuários.');
            } else {
                $usuarios = array();
                foreach ($result->result() as $value) {
                    $value->email != NULL ? array_push($usuarios, $value->email) : '';
                }
                return $usuarios;
            }
        } catch (ExceptionDAO $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
}